package top.arwtec.mcm.service.impl;

import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.BeanUtils;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import top.arwtec.mcm.entity.*;
import top.arwtec.mcm.enums.UserEnum;
import top.arwtec.mcm.mapper.PasswordMapper;
import top.arwtec.mcm.mapper.RoleMapper;
import top.arwtec.mcm.mapper.UserMapper;
import top.arwtec.mcm.mapper.UserRoleMapper;
import top.arwtec.mcm.service.UserInfoService;

import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @author liyin
 */
@RequiredArgsConstructor
@Service
public class UserInfoServiceImpl extends ServiceImpl<UserMapper,UserInfo> implements UserInfoService {

    private final UserMapper userMapper;
    private final PasswordMapper passwordMapper;
    private BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
    private final UserRoleMapper userRoleMapper;
    private final RoleMapper roleMapper;

    @Override
    public UserDetails getUserInfo(String name) {
        LambdaQueryWrapper<UserInfo> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(UserInfo::getUsername,name).or().eq(UserInfo::getMail,name).or().eq(UserInfo::getPhone,name);
        UserInfo user = getUserInfo(wrapper);
        if (user == null) {
            throw new UsernameNotFoundException(UserEnum.USER_NOT_EXIST.getMsg());
        }
        LambdaQueryWrapper<UserPassword> lqw = new LambdaQueryWrapper<>();
        lqw.eq(UserPassword::getUserId,user.getId());
        lqw.eq(UserPassword::isEnabled,true);
        UserPassword password = passwordMapper.selectOne(lqw);
        LambdaQueryWrapper<UserRole> lqw1 = Wrappers.lambdaQuery();
        lqw1.eq(UserRole::getUserId,user.getId());
        List<UserRole> userRoles = userRoleMapper.selectList(lqw1);
        Set<Long> roleIds = userRoles.parallelStream().map(UserRole::getRoleId).collect(Collectors.toSet());
        LambdaQueryWrapper<Role> lqw2 = Wrappers.lambdaQuery();
        lqw2.in(Role::getId,roleIds);
        List<Role> roleList = roleMapper.selectList(lqw2);
        Set<GrantedAuthority> authorities = roleList.parallelStream().map(role -> new SimpleGrantedAuthority(role.getRoleKey())).collect(Collectors.toSet());
        String passwd = encoder.encode("123456");
        boolean enable = true;
        boolean accountNonExpired = false;
        boolean credentialsNonExpired = false;
        boolean accountNonLocked = false;
        if (password != null) {
            if (password.getPassword() != null) {
                passwd = password.getPassword();
            }
            enable = password.isEnabled();
            accountNonExpired = password.isAccountNonExpired();
            credentialsNonExpired = password.isCredentialsNonExpired();
            accountNonLocked = password.isAccountNonLocked();
        }
        User.UserBuilder builder = User.builder();
        builder.username(user.getUsername()).password(passwd)
                .accountExpired(accountNonExpired)
                .accountLocked(accountNonLocked)
                .disabled(!enable)
                .credentialsExpired(credentialsNonExpired).authorities(authorities);
        return builder.build();
    }

    @Override
    public UserInfo getUserInfo(Wrapper<UserInfo> userWrapper) {
        return userMapper.selectOne(userWrapper);
    }

    @Override
    public List<UserInfo> getUserInfoList(Wrapper<UserInfo> userWrapper) {
        return userMapper.selectList(userWrapper);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean saveUserInfo(UserInfo user) {
        validUser(user);
        boolean flag = userMapper.insert(user) > 0;
        if (flag) {
            UserPassword password = user.getUserPassword();
            if (password == null) {
                throw new RuntimeException("密码不能为空");
            }
            password.setUserId(user.getId());
            passwordMapper.insert(password);
        }
        return false;
    }
    @Override
    public boolean updateUserInfo(UserInfo user) {
        return userMapper.updateById(user) > 0;
    }

    @Override
    public boolean deleteUserInfo(Long id) {
        return userMapper.deleteById(id) > 0;
    }

    private void validUser(UserInfo user) {
        if (user.getUsername() == null) {
            throw new RuntimeException("用户名不能为空");
        }
        LambdaQueryWrapper<UserInfo> lqw = Wrappers.lambdaQuery();
        lqw.eq(user.getUsername()!= null, UserInfo::getUsername,user.getUsername());
        lqw.eq(user.getMail()!= null, UserInfo::getMail,user.getMail());
        lqw.eq(user.getPhone()!= null, UserInfo::getPhone,user.getPhone());
        long res = userMapper.selectCount(lqw);
        if (res > 0) {
            throw new RuntimeException("手机、邮箱或者手机号已被注册");
        }
    }
}
